<?php

/**
 * 操作类型抽象类  抽象产品
 *
 * Class Operation
 * @package Baijunyao\DesignPatterns\FactoryMethod
 */
abstract class Operation
{
    /**
     * 运算符号左边的值
     *
     * @var int
     */
    protected $numberA = 0;

    /**
     * 运算符号右边的值
     *
     * @var int
     */
    protected $numberB = 0;

    /**
     * 计算结果
     *
     * @return mixed
     */
    abstract public function getResult();

    /**
     * 给 numberA 赋值
     *
     * @param $number
     */
    public function setNumberA($number)
    {
        $this->numberA = $number;
    }

    /**
     * 给 numberB 赋值
     *
     * @param $number
     */
    public function setNumberB($number)
    {
        $this->numberB = $number;
    }

}

/**
 * 加法 具体产品
 *
 * Class Add
 * @package Baijunyao\DesignPatterns\FactoryMethod
 */
class Add extends Operation
{
    /**
     * 计算结果
     *
     * @return int
     */
    public function getResult()
    {
        return $this->numberA + $this->numberB;
    }
}


/**
 * 减法 具体产品
 *
 * Class Sub
 * @package Baijunyao\DesignPatterns\FactoryMethod
 */
class Sub extends Operation
{
    /**
     * 计算结果
     *
     * @return int|mixed
     */
    public function getResult()
    {
        return $this->numberA - $this->numberB;
    }
}


/**
 * 乘法 具体产品
 *
 * Class Mul
 * @package Baijunyao\DesignPatterns\FactoryMethod
 */
class Mul extends Operation
{
    /**
     * 计算结果
     *
     * @return float|int
     */
    public function getResult()
    {
        return $this->numberA * $this->numberB;
    }
}


/**
 * 除法 具体产品
 *
 * Class Div
 * @package Baijunyao\DesignPatterns\FactoryMethod
 */
class Div extends Operation
{
    /**
     * 计算结果
     *
     * @return float|int
     */
    public function getResult()
    {
        if ($this->numberB == 0) {
            throw new \InvalidArgumentException('除数不能为0');
        }
        return $this->numberA / $this->numberB;
    }
}

/**
 * 工厂抽象类
 *
 * Class Factory
 * @package Baijunyao\DesignPatterns\FactoryMethod
 */
abstract class Factory
{
    /**
     * 创建产品
     *
     * @return mixed
     */
    abstract public function create();
}

/**
 * 加法工厂 具体工厂
 *
 * Class AddFactory
 * @package Baijunyao\DesignPatterns\FactoryMethod
 */
class AddFactory extends Factory
{
    /**
     * 创建加法产品类
     *
     * @return Add
     */
    public function create()
    {
        return new Add();
    }
}


/**
 * 减法工厂 具体工厂
 *
 * Class SubFactory
 * @package Baijunyao\DesignPatterns\FactoryMethod
 */
class SubFactory extends Factory
{
    /**
     * 创建减法产品类
     *
     * @return Sub
     */
    public function create()
    {
        return new Sub();
    }
}


/**
 * 乘法工厂 具体工厂
 *
 * Class MulFactory
 * @package Baijunyao\DesignPatterns\FactoryMethod
 */
class MulFactory extends Factory
{
    /**
     * 创建乘法产品类
     *
     * @return Mul
     */
    public function create()
    {
        return new Mul();
    }
}


/**
 * 除法工厂 具体工厂
 *
 * Class DivFactory
 * @package Baijunyao\DesignPatterns\FactoryMethod
 */
class DivFactory extends Factory
{
    /**
     * 创建除法产品类
     *
     * @return Div
     */
    public function create()
    {
        return new Div();
    }
}


/**
 * 客户端
 *
 * Class Client
 * @package Baijunyao\DesignPatterns\FactoryMethod
 */
class Client
{
    /**
     * 不好的示例   直接 new 具体的产品
     */
    public function bad()
    {
        // 计算 1+2
        $operation = new Add();
        $operation->setNumberA(1);
        $operation->setNumberB(2);
        $result = $operation->getResult();
        echo $result;

        echo '<br>';

        // 计算 3+4
        $operation = new Add();
        $operation->setNumberA(3);
        $operation->setNumberB(4);
        $result = $operation->getResult();
        echo $result;
    }

    /**
     * 好的示例  new 产品对应的工厂
     */
    public function good()
    {
        $factory = new AddFactory();
        $operation = $factory->create();
        $operation->setNumberA(1);
        $operation->setNumberB(2);
        $result = $operation->getResult();
        echo $result;
    }
}


$client = new Client();
$client->bad();
echo '<br>';
$client->good();